package com.amz.fc.base;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class AmzXmlCfgUtil {
	public static void main(String[] args){
	}
	
	@SuppressWarnings({"rawtypes"})
	public String getReadSql(Class actionClass,String sqlName, Map<String,String> param){
		String ret = "";
		String path = actionClass.getResource("").getPath();
		String fileName = path + actionClass.getSimpleName() + ".xml";
		File inputXml = new File(fileName);
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(inputXml);
			List sqls = document.selectNodes("//sqls/sql");
			for (Object sql : sqls) {
				Element s = (Element)sql;
				String name = s.valueOf("@name");
				if(!sqlName.equals(name)) continue;
				String sqlVal = s.getText();
				ret += sqlVal;
				List ifNodes = s.selectNodes("if");
				for (Object ifNode : ifNodes) {
					Element ifElm = (Element)ifNode;
					String assertStrs = ifElm.valueOf("@assert");
					if(compare(assertStrs, param)){
						String assertSql = ifElm.getText();
						ret += assertSql;
					}
				}
			}
			replaceReadSqlParam(ret,param);
		} catch (DocumentException e) {
			System.out.println(e.getMessage());
		}
		return ret;
	}
	
	public SaveSqlInfo getSaveSqlInfo(Class<?> actionClass,String sqlName, Map<String,?> param){
		SaveSqlInfo saveSqlInfo = new SaveSqlInfo();
		String path = actionClass.getResource("").getPath();
		String fileName = path + actionClass.getSimpleName() + ".xml";
		File inputXml = new File(fileName);
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(inputXml);
			List<?> sqls = document.selectNodes("//sqls/sql");
			String cfgSql = "";
			for (Object sql : sqls) {
				Element s = (Element)sql;
				String name = s.valueOf("@name");
				if(!sqlName.equals(name)) continue;
				String sqlVal = s.getText();
				cfgSql += sqlVal;
				List<?> ifNodes = s.selectNodes("if");
				for (Object ifNode : ifNodes) {
					Element ifElm = (Element)ifNode;
					String assertStrs = ifElm.valueOf("@assert");
					if(compare(assertStrs, param)){
						String assertSql = ifElm.getText();
						cfgSql += assertSql;
					}
				}
			}
			
			cfgSql = cfgSql.trim();
			Vector preSqlArgsStrVal = new Vector();
			//分析SQL命令，得到保存的表名，字段名，pk字段名
			Pattern pUpdate = Pattern.compile("(?i)^UPDATE\\s+(.+)\\s+SET\\s+(.+)\\s+(WHERE)?",Pattern.MULTILINE);
			Pattern pInsert = Pattern.compile("(?i)^INSERT INTO\\s+(.+)\\s*\\((.+)\\)\\s+VALUES\\s*\\(",Pattern.MULTILINE);
			Matcher mUpdate = pUpdate.matcher(cfgSql);
			Matcher mInsert = pInsert.matcher(cfgSql);
			boolean isUpdate = mUpdate.find();
			boolean isInsert = mInsert.find();
			String tableName = null;
			String saveColStrVal = null;
			String saveColNames[] = null;
			String firstSaveColName = null;
			if(isInsert){
				tableName = mInsert.group(1).trim();
				saveColStrVal = mInsert.group(2).trim();
				saveColNames = StringUtils.split(saveColStrVal,",");
				firstSaveColName = saveColNames[0].trim();
			}
			if(isUpdate){
				tableName = mUpdate.group(1).trim();
				saveColStrVal = mUpdate.group(2).trim();
				saveColNames = StringUtils.split(saveColStrVal,"=?,");
			}
			
			//去数据库中查类型
			String metaDataSql = "SELECT "; 
			for (String colName : saveColNames) {
				metaDataSql += colName + ",";
				preSqlArgsStrVal.add(param.get(colName.trim()));
			}
			metaDataSql = metaDataSql.substring(0,metaDataSql.lastIndexOf(","));
			metaDataSql += " LIMIT 0";
			
			saveSqlInfo.setPrepareSql(cfgSql);
			saveSqlInfo.setMetaDataSql(metaDataSql);
			//saveSqlInfo.setPrepareArgsStrVal(preSqlArgsStrVal.toArray(new String[preSqlArgsStrVal.size()]));
			saveSqlInfo.setPkColName(firstSaveColName);
			saveSqlInfo.setTableName(tableName);
		} catch (DocumentException e) {
			System.out.println(e.getMessage());
		}
		return saveSqlInfo;
	}
	
	public void replaceReadSqlParam(String sql,Map<String,String> param){
		Set<String> keys = param.keySet();
		for (String key : keys) {
			Object val = param.get(key);
			String strVal = String.valueOf(val);
			sql.replaceAll("#{" + key + "}", strVal);
		}
	}

	  
	public void createXml(String fileName) {
		Document document = DocumentHelper.createDocument();
		Element employees = document.addElement("employees");
		Element employee = employees.addElement("employee");
		Element name = employee.addElement("name");
		name.setText("ddvip");
		Element sex = employee.addElement("sex");
		sex.setText("m");
		Element age = employee.addElement("age");
		age.setText("29");
		try {
			Writer fileWriter = new FileWriter(fileName);
			XMLWriter xmlWriter = new XMLWriter(fileWriter);
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}

	@SuppressWarnings("rawtypes")
	public void parserXml(String fileName) {
		File inputXml = new File(fileName);
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(inputXml);
			Element employees = document.getRootElement();
			for (Iterator i = employees.elementIterator(); i.hasNext();) {
				Element employee = (Element) i.next();
				for (Iterator j = employee.elementIterator(); j.hasNext();) {
					Element node = (Element) j.next();
					System.out.println(node.getName() + ":" + node.getText());
				}
			}
		} catch (DocumentException e) {
			System.out.println(e.getMessage());
		}
		System.out.println("dom4j parserXml");
	}   
	
	/**
	 * < 小于
	 * > 大于 
	 * <= 小于或等于
	 * >= 大于或等于 
	 * == 等于 
	 * != 不等于 
	 * && 而且 (And) 
	 * || 或者
	 * ! 非 (Not)
	 * LIKE 字符串比较
	 * NOT LIKE 字符串比较
	 * 暂时只支持一些简单运算
	 */
	public boolean compare(String assertStrs,Map<String,?> data){
		if(data.isEmpty()) return false;
		boolean ret = true;
		String[] andOrKeys = {"&&","||"};
		String[] numCompareKeys = {"<",">","<=",">=","==","!="};
		String[] stringCompareKeys = {"LIKE","NOT LIKE"};
		Vector<Boolean> andResults  = new Vector<Boolean>();
		Vector<Boolean> orResults  = new Vector<Boolean>();
		for (String andOr : andOrKeys) {
			String[] assertStrAry = StringUtils.split(assertStrs,andOr);
			
			for (String assertStr : assertStrAry) {
				boolean retTemp = false;
				for (String numCompareKey : numCompareKeys) {
					if(assertStr.indexOf(numCompareKey)<0) continue;
					String[] compareVals = StringUtils.split(assertStr,numCompareKey);
					String v1 = (String) data.get(compareVals[0]);
					String v2 = (String) data.get(compareVals[1]);
					if(v2==null) v2 = compareVals[1];
					BigDecimal bv1 = new BigDecimal(v1);
					BigDecimal bv2 = new BigDecimal(v2);
					int compareResult = bv1.compareTo(bv2);
					switch (compareResult) {
					case -1:
						if(numCompareKey.equals("<")||numCompareKey.equals("<=")||numCompareKey.equals("!=")) retTemp = true;
						break;
					case 0:
						if(numCompareKey.equals("==")||numCompareKey.equals("<=")||numCompareKey.equals(">=")) retTemp = true;
						break;
					case 1:
						if(numCompareKey.equals(">")||numCompareKey.equals(">=")||numCompareKey.equals("!=")) retTemp = true;
						break;
					}
					if(andOr.equals("&&")) andResults.add(retTemp);
					else if(andOr.equals("||")) orResults.add(retTemp);
					
				}
				
				for (String stringCompareKey : stringCompareKeys) {
					if(assertStr.indexOf(stringCompareKey)<0) continue;
					String[] compareVals = StringUtils.split(assertStr,stringCompareKey);
					String v1 = (String)data.get(compareVals[0]);
					String v2 = (String)data.get(compareVals[1]);
					if(v2==null) v2 = compareVals[1];
					boolean compareResult = StringUtils.equals(v1, v2);
					if(compareResult&&stringCompareKey.equals("LIKE")) retTemp = true;
					if(!compareResult&&stringCompareKey.equals("NOT LIKE")) retTemp = true;

					if(andOr.equals("&&")) andResults.add(retTemp);
					else if(andOr.equals("||")) orResults.add(retTemp);
				}
			}
			
		}
		if(andResults.size()>1){
			for (Boolean andResult : andResults) {
				ret = true;
				if(ret&&andResult) ret = true;
				else ret = false;
			}
		}else{
			ret = andResults.get(0);
		}
		
		if(orResults.size()>1){
			for (Boolean andResult : andResults) {
				ret = true;
				if(ret||andResult) ret = true;
				else ret = false;
			}
		}else{
			ret = orResults.get(0);
		}
				return ret;
		
	}
	
	
}
